﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using TST.SharePointObjects.WebControls;
using Microsoft.SharePoint;
using Microsoft.SharePoint.WebControls;
using System.Data;

namespace TST.SharePointObjects.WebControls
{
    public class ObjectReferenceGrid : UserControl
    {
        protected DropDownList selectReferenceType;
        protected DropDownList selectScope;
        protected TextBox searchReferences;
        protected SortGrid gridReferences;
        protected Label labelSelectComment;
        private SharePointObjectsDatabase _database;
        private ObjectDataSource _filterableDatasource;
        private const int ObjectReferencePageSize = 50;
        private const int MaxObjectReferenceCount = 4000;
        protected Label labelTitle;

        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);
            SetupSearch();
        }

        internal string Title
        {
            get { return labelTitle.Text; }
            set { labelTitle.Text = value; }
        }

        private String CurrentSelectedObjectId
        {
            get
            {
                if (ViewState["CurrentSelectedObject"] == null)
                    return null;
                return (String)ViewState["CurrentSelectedObject"];
            }
            set
            {
                ViewState["CurrentSelectedObject"] = value;
            }
        }

        private String CurrentSelectedIndexId
        {
            get
            {
                if (ViewState["CurrentSelectedIndexId"] == null)
                    return null;
                return (String)ViewState["CurrentSelectedIndexId"];
            }
            set
            {
                ViewState["CurrentSelectedIndexId"] = value;
            }
        }

        private String CurrentSiteObjectName
        {
            get
            {
                if (ViewState["CurrentSiteObjectName"] == null)
                    return null;
                return (String)ViewState["CurrentSiteObjectName"];
            }
            set
            {
                ViewState["CurrentSiteObjectName"] = value;
            }
        }

        private SiteObjectType CurrentSiteObjectType
        {
            get
            {
                if (ViewState["CurrentSiteObjectType"] == null)
                    return SiteObjectType.All;
                return (SiteObjectType)ViewState["CurrentSiteObjectType"];
            }
            set
            {
                ViewState["CurrentSiteObjectType"] = value;
            }
        }

        public SharePointObjectsDatabase Database
        {
            get { return _database; }
            set { _database = value; }
        }

        protected override void CreateChildControls()
        {
            base.CreateChildControls();

            SetupReferences();

            // Add controls for filtering
            _filterableDatasource = new ObjectDataSource();
            _filterableDatasource.ID = String.Format("SODataSource_{0}", this.ID);
            this.Controls.Add(_filterableDatasource);
            SPGridViewPager pager = new SPGridViewPager();
            pager.ID = String.Format("SOPager_{0}", this.ID);
            pager.GridViewId = gridReferences.Grid.ID;
            Controls.Add(pager);
            _filterableDatasource.SelectMethod = "SelectData";
            _filterableDatasource.TypeName = this.GetType().AssemblyQualifiedName;
            _filterableDatasource.ObjectCreating += new ObjectDataSourceObjectEventHandler(_filterableDatasource_ObjectCreating);

            gridReferences.Grid.DataSourceID = _filterableDatasource.ID;
            gridReferences.EnableViewState = true;

            gridReferences.Grid.FilteredDataSourcePropertyFormat = "{1} = '{0}'";
            gridReferences.Grid.Sorting += new GridViewSortEventHandler(_grid_Sorting);
            _filterableDatasource.Filtering += new ObjectDataSourceFilteringEventHandler(_filterableDatasource_Filtering);

            pager.Visible = true;
        }

        protected sealed override void LoadViewState(object savedState)
        {
            base.LoadViewState(savedState);
            if (Context.Request.Form["__EVENTARGUMENT"] != null &&
                 Context.Request.Form["__EVENTARGUMENT"].EndsWith("__ClearFilter__"))
            {
                // Clear FilterExpression
                ViewState.Remove("FilterExpression");
            }
        }

        private void _grid_Sorting(object sender, GridViewSortEventArgs e)
        {
            if (ViewState["FilterExpression"] != null)
            {
                String filter = (string)ViewState["FilterExpression"];
                if (String.IsNullOrEmpty(_filterableDatasource.FilterExpression))
                {
                    _filterableDatasource.FilterExpression = filter;
                }
            }
        }
        private void _filterableDatasource_Filtering(object sender, ObjectDataSourceFilteringEventArgs e)
        {
            ViewState["FilterExpression"] = ((ObjectDataSourceView)sender).FilterExpression;
        }

        private void _filterableDatasource_ObjectCreating(object sender, ObjectDataSourceEventArgs e)
        {
            e.ObjectInstance = this;
        }

        private void SetupSearch()
        {
            if (!Page.IsPostBack)
            {
                selectReferenceType.AutoPostBack = true;

                // Search scope
                selectScope.AutoPostBack = true;
                selectScope.Items.Add(new ListItem("-- Select a search scope --", string.Empty));
                ListItem defaultItem = new ListItem(Globals.GetScopeDescription(ObjectReferenceScope.Web), ObjectReferenceScope.Web.ToString());
                defaultItem.Selected = true;
                selectScope.Items.Add(defaultItem);
                selectScope.Items.Add(new ListItem(Globals.GetScopeDescription(ObjectReferenceScope.SiteCollection), ObjectReferenceScope.SiteCollection.ToString()));
                selectScope.Items.Add(new ListItem(Globals.GetScopeDescription(ObjectReferenceScope.WebApplication), ObjectReferenceScope.WebApplication.ToString()));
                selectScope.Items.Add(new ListItem(Globals.GetScopeDescription(ObjectReferenceScope.Farm), ObjectReferenceScope.Farm.ToString()));

                // Search reference
                searchReferences.AutoPostBack = true;
                searchReferences.MaxLength = Globals.NAMESEARCHLENGTH;
            }
        }

        private void SetupReferenceTypes(SiteObject selectedObject)
        {
            // Select reference
            selectReferenceType.Items.Clear();
            selectReferenceType.Items.Add(new ListItem("-- Select a reference type --", string.Empty));
            switch (selectedObject.SiteObjectType)
            {
                case SiteObjectType.ContentType:
                    selectReferenceType.Items.Add(new ListItem(Globals.GetReferenceTypeDescription(ObjectReferenceType.ContentTypeList), ObjectReferenceType.ContentTypeList.ToString()));
                    selectReferenceType.Items.Add(new ListItem(Globals.GetReferenceTypeDescription(ObjectReferenceType.ContentTypeListItem), ObjectReferenceType.ContentTypeListItem.ToString()));
                    selectReferenceType.Items.Add(new ListItem(Globals.GetReferenceTypeDescription(ObjectReferenceType.ContentTypeParent), ObjectReferenceType.ContentTypeParent.ToString()));
                    break;
                case SiteObjectType.FeatureDefinition:
                    selectScope.SelectedValue = ObjectReferenceScope.Farm.ToString();
                    selectReferenceType.Items.Add(new ListItem(Globals.GetReferenceTypeDescription(ObjectReferenceType.FeatureDefinitionFarm), ObjectReferenceType.FeatureDefinitionFarm.ToString()));
                    selectReferenceType.Items.Add(new ListItem(Globals.GetReferenceTypeDescription(ObjectReferenceType.FeatureDefinitionWebApplication), ObjectReferenceType.FeatureDefinitionWebApplication.ToString()));
                    selectReferenceType.Items.Add(new ListItem(Globals.GetReferenceTypeDescription(ObjectReferenceType.FeatureDefinitionSite), ObjectReferenceType.FeatureDefinitionSite.ToString()));
                    selectReferenceType.Items.Add(new ListItem(Globals.GetReferenceTypeDescription(ObjectReferenceType.FeatureDefinitionWeb), ObjectReferenceType.FeatureDefinitionWeb.ToString()));
                    break;
                case SiteObjectType.SharePointGroup:
                    selectReferenceType.Items.Add(new ListItem(Globals.GetReferenceTypeDescription(ObjectReferenceType.SharePointGroupWeb), ObjectReferenceType.SharePointGroupWeb.ToString()));
                    selectReferenceType.Items.Add(new ListItem(Globals.GetReferenceTypeDescription(ObjectReferenceType.SharePointGroupList), ObjectReferenceType.SharePointGroupList.ToString()));
                    selectReferenceType.Items.Add(new ListItem(Globals.GetReferenceTypeDescription(ObjectReferenceType.SharePointGroupFolder), ObjectReferenceType.SharePointGroupFolder.ToString()));
                    selectReferenceType.Items.Add(new ListItem(Globals.GetReferenceTypeDescription(ObjectReferenceType.SharePointGroupItem), ObjectReferenceType.SharePointGroupItem.ToString()));
                    break;
                case SiteObjectType.SiteColumn:
                    selectReferenceType.Items.Add(new ListItem(Globals.GetReferenceTypeDescription(ObjectReferenceType.SiteColumnContentType), ObjectReferenceType.SiteColumnContentType.ToString()));
                    selectReferenceType.Items.Add(new ListItem(Globals.GetReferenceTypeDescription(ObjectReferenceType.SiteColumnList), ObjectReferenceType.SiteColumnList.ToString()));
                    selectReferenceType.Items.Add(new ListItem(Globals.GetReferenceTypeDescription(ObjectReferenceType.SiteColumnListItem), ObjectReferenceType.SiteColumnListItem.ToString()));
                    break;
            }
        }

        //private void GetReferenceInfo(SiteObject selected)
        //{
        //    if (selected != null)
        //    {
        //        // Set details for selected item.
        //        SPField field = SPContext.Current.Web.Fields[new Guid(selected.Id)];
        //        selectedObject.SelectedObjectLabel.Text = string.Format("{0} (internal name={1})", selected.Name, field.InternalName);
        //        rowSiteObjectOptionsHeader.Visible = true;
        //        rowSiteObjectOptions.Visible = true;
        //        //ObjectReferenceType refType = ObjectReferenceType.Unknown;
        //        //if (selectReferenceType.SelectedValue != string.Empty)
        //        //{
        //        //    refType = (ObjectReferenceType)Enum.Parse(typeof(ObjectReferenceType), selectReferenceType.SelectedValue);
        //        //}
        //        //ObjectReferenceScope refScope = ObjectReferenceScope.Everything;
        //        //if (selectScope.SelectedValue != string.Empty)
        //        //{
        //        //    refScope = (ObjectReferenceScope)Enum.Parse(typeof(ObjectReferenceScope), selectScope.SelectedValue);
        //        //}

        //        //ObjectReferenceStore store = new ObjectReferenceStore(SPContext.Current.Site.ID, SPContext.Current.Web.ID, VersionInfo.License.LicensingMode);
        //        //ObjectReferenceSelection select = new ObjectReferenceSelection(refScope, refType, ctype.Id, searchReferences.Text);
        //        //_references = store.GetObjectReferences(select);
        //        //if (_references != null)
        //        //{
        //        //    gridReferences.Grid.DataSource = _references.Items;
        //        //    labelSelectComment.Text = "In the list below you will find...";
        //        //    //cellDetails.Visible = true;
        //        //}
        //    }
        //    //else
        //    //{
        //    //    labelSelectComment.Text = "Select one of the content types in the list.";
        //    //}
        //}

        private void SetupReferences()
        {
            gridReferences.Grid.Columns.Clear();

            String filterFields = String.Empty;
            gridReferences.Grid.AllowPaging = true;
            gridReferences.Grid.PageSize = ObjectReferencePageSize;
            gridReferences.Grid.Columns.Clear();

            HyperLinkField nameColumn = new HyperLinkField();
            nameColumn.HeaderStyle.HorizontalAlign = HorizontalAlign.Left;
            nameColumn.ItemStyle.HorizontalAlign = HorizontalAlign.Left;
            nameColumn.DataNavigateUrlFields = new string[] { "Url" };
            nameColumn.DataNavigateUrlFormatString = "{0}";
            nameColumn.SortExpression = "Name";
            nameColumn.DataTextField = "Name";
            nameColumn.HeaderText = "Name";
            nameColumn.Target = "_blank";
            filterFields += ",";
            gridReferences.Grid.Columns.Add(nameColumn);

            BoundField valueColumn = new BoundField();
            valueColumn.HeaderStyle.HorizontalAlign = HorizontalAlign.Left;
            valueColumn.ItemStyle.HorizontalAlign = HorizontalAlign.Left;
            valueColumn.SortExpression = "ReferenceTypeDescription";
            valueColumn.DataField = "ReferenceTypeDescription";
            valueColumn.HeaderText = "Object type";
            valueColumn.HtmlEncode = false;
            filterFields += "ReferenceTypeDescription,";
            gridReferences.Grid.Columns.Add(valueColumn);

            HyperLinkField siteColumn = new HyperLinkField();
            siteColumn.HeaderStyle.HorizontalAlign = HorizontalAlign.Left;
            siteColumn.ItemStyle.HorizontalAlign = HorizontalAlign.Left;
            siteColumn.DataNavigateUrlFields = new string[] { "SiteUrl" };
            siteColumn.DataNavigateUrlFormatString = "{0}";
            siteColumn.SortExpression = "SiteTitle";
            siteColumn.DataTextField = "SiteTitle";
            siteColumn.Target = "_blank";
            siteColumn.HeaderText = "Site";
            filterFields += "SiteTitle,";
            gridReferences.Grid.Columns.Add(siteColumn);

            HyperLinkField listColumn = new HyperLinkField();
            listColumn.HeaderStyle.HorizontalAlign = HorizontalAlign.Left;
            listColumn.ItemStyle.HorizontalAlign = HorizontalAlign.Left;
            listColumn.DataNavigateUrlFields = new string[] { "ListUrl" };
            listColumn.DataNavigateUrlFormatString = "{0}";
            listColumn.SortExpression = "ListTitle";
            listColumn.DataTextField = "ListTitle";
            listColumn.Target = "_blank";
            listColumn.HeaderText = "List";
            filterFields += "ListTitle";
            gridReferences.Grid.Columns.Add(listColumn);

            gridReferences.Visible = false;

            gridReferences.Grid.AllowFiltering = true;
            gridReferences.Grid.FilterDataFields = filterFields.TrimEnd(new char[] { ',' });
            gridReferences.Grid.FilteredDataSourcePropertyName = "FilterExpression";
        }

        protected override void OnPreRender(EventArgs e)
        {
            base.OnPreRender(e);
            gridReferences.DataBind();
            gridReferences.Visible = true;
        }

        internal void GetReferenceInfo(SiteObject selected, LicensingMode licensingMode)
        {
            if (Database != null && selected != null && selected.IndexId != null)
            {
                if (CurrentSelectedObjectId == null || string.Compare(selected.Id, CurrentSelectedObjectId) != 0)
                {
                    SetupReferenceTypes(selected);
                }
                CurrentSelectedObjectId = selected.Id;
                CurrentSelectedIndexId = selected.IndexId;
                CurrentSiteObjectType = selected.SiteObjectType;
                CurrentSiteObjectName = selected.Name;
            }
        }

        public DataTable SelectData()
        {
            if (CurrentSelectedIndexId == null)
            {
                return null;
            }
            DataTable references;
            ObjectReferenceType refType = ObjectReferenceType.Unknown;
            if (selectReferenceType.SelectedValue != string.Empty)
            {
                refType = (ObjectReferenceType)Enum.Parse(typeof(ObjectReferenceType), selectReferenceType.SelectedValue);
            }
            ObjectReferenceScope refScope = ObjectReferenceScope.Farm;
            if (selectScope.SelectedValue != string.Empty)
            {
                refScope = (ObjectReferenceScope)Enum.Parse(typeof(ObjectReferenceScope), selectScope.SelectedValue);
            }

            VersionInfo info = new VersionInfo(Database);
            ObjectReferenceStore store = new ObjectReferenceStore(SPContext.Current.Site.ID, SPContext.Current.Web.ID, info.License.LicensingMode, Database);
            ObjectReferenceSelection select = new ObjectReferenceSelection(refScope, refType, CurrentSelectedIndexId, searchReferences.Text);
            references = store.GetObjectReferencesAsTable(select, true, MaxObjectReferenceCount);
            if (references != null)
            {
                SetReferenceComment(references);
                return references;
            }
            return null;
        }

        private void SetReferenceComment(DataTable referenceObjects)
        {
            if (referenceObjects == null || referenceObjects.Rows.Count == 0)
            {
                switch (CurrentSiteObjectType)
                {
                    case SiteObjectType.ContentType:
                        labelSelectComment.Text = String.Format("No SharePoint Objects are using content type '{0}' in the selected scope, or it is not indexed.", CurrentSiteObjectName);
                        break;
                    case SiteObjectType.FeatureDefinition:
                        labelSelectComment.Text = String.Format("No SharePoint Objects are using feature definition '{0}' in the selected scope, or it is not indexed.", CurrentSiteObjectName);
                        break;
                    case SiteObjectType.SharePointGroup:
                        labelSelectComment.Text = String.Format("No SharePoint Objects are using SharePoint group '{0}' in the selected scope, or it is not indexed.", CurrentSiteObjectName);
                        break;
                    case SiteObjectType.SiteColumn:
                        labelSelectComment.Text = String.Format("No SharePoint Objects are using site column '{0}' in the selected scope, or it is not indexed.", CurrentSiteObjectName);
                        break;
                }
            }
            else
            {
                switch (CurrentSiteObjectType)
                {
                    case SiteObjectType.ContentType:
                        labelSelectComment.Text = String.Format("{1} SharePoint Objects using content type '{0}' in the selected scope.", CurrentSiteObjectName, referenceObjects.Rows.Count);
                        break;
                    case SiteObjectType.FeatureDefinition:
                        labelSelectComment.Text = String.Format("{1} SharePoint Objects using feature definition '{0}' in the selected scope.", CurrentSiteObjectName, referenceObjects.Rows.Count);
                        break;
                    case SiteObjectType.SharePointGroup:
                        labelSelectComment.Text = String.Format("{1} SharePoint Objects using SharePoint group '{0}' in the selected scope.", CurrentSiteObjectName, referenceObjects.Rows.Count);
                        break;
                    case SiteObjectType.SiteColumn:
                        labelSelectComment.Text = String.Format("{1} SharePoint Objects are using site column '{0}' in the selected scope.", CurrentSiteObjectName, referenceObjects.Rows.Count);
                        break;
                }
                if (referenceObjects.Rows.Count == MaxObjectReferenceCount)
                {
                    labelSelectComment.Text += " The list contains the maximum number of items.";
                }
            }
        }

    }
}
